(import
  (except (rnrs base) let-values map error)
  (only (guile)
        lambda* λ
        array-ref)
  (ice-9 format)
  ;; list utils
  (prefix (srfi srfi-1) srfi-1:)
  ;; for unit testing forms
  (srfi srfi-64)
  ;; for list procedures
  (srfi srfi-1)
  ;; module under test
  (lf2-data-crypt)
  (prefix (logging) log:)
  (rnrs bytevectors)
  (bytevector-utils))


(test-begin "crypt-test")

(test-group
 "shift"

 (test-assert "shift-01"
   (= (shift 12 24 #:rest-class 256)
      36))

 (test-assert "shift-02"
   (= (shift 12 24 #:rest-class 36)
      0))

 (test-assert "shift-03"
   (= (shift 68 24 #:rest-class 36)
      20)))

(test-group
 "reverse-shift"

 (test-assert "reverse-shift-01"
   (= (reverse-shift 12 24 #:rest-class 256)
      244))

 (test-assert "reverse-shift-02"
   (= (reverse-shift 12 3 #:rest-class 36)
      9))

 (test-assert "reverse-shift-03"
   (= (reverse-shift 76 4 #:rest-class 36)
      0)))


(test-group
 "encrypt"

 (test-assert "encrypt-u8-01"
   (= (encrypt-u8 100 0 (string->bytevector "abc"))
      197))

 (test-assert "encrypt-u8-02"
   (= (encrypt-u8 100 1 (string->bytevector "abc"))
      198))

 (test-assert "encrypt-u8-03"
   (= (encrypt-u8 100 2 (string->bytevector "abc"))
      199))

 (test-assert "encrypt-u8-04"
   (= (encrypt-u8 100 1 (string->bytevector "abc"))
      198))

 (test-assert "encrypt-u8-05"
   (= (encrypt-u8 100 2 (string->bytevector "abc"))
      199))

 (test-assert "encrypt-u8-06"
   (= (encrypt-u8 100 3 (string->bytevector "abc"))
      197))

 (test-assert "encrypt-u8-07"
   (= (encrypt-u8 100 4 (string->bytevector "abc"))
      198))

 (test-assert "encrypt-u8-08"
   (= (encrypt-u8 100 5 (string->bytevector "abc"))
      199))

 (test-assert "encrypt-01"
   (let ([payload "this is some payload"]
         [secret "cool-secret"])
     (begin
       ;; write file with trash bytes and some known content after the trash bytes
       (call-with-output-file "test.dat"
         (λ (port)
           (encrypt payload
                    #:port port
                    #:secret secret
                    #:trash-bytes trash-bytes)))
       (let ([string-from-file
              (call-with-input-file "test.dat"
                (λ (port)
                  (decrypt #:port port
                           #:secret secret
                           #:num-ignored-bytes (bytevector-length trash-bytes))))])
         (log:debug "string written to file:" payload)
         (log:debug "string from file:" string-from-file)
         (string=? string-from-file payload)))))

 (test-assert "encrypt-02"
   (let ([payload ">)'$/)=123()[}]{}"]
         [secret "123-another cool-secret"])
     (begin
       ;; write file with trash bytes and some known content after the trash bytes
       (call-with-output-file "test.dat"
         (λ (port)
           (encrypt payload
                    #:port port
                    #:secret secret
                    #:trash-bytes trash-bytes)))
       (let ([string-from-file
              (call-with-input-file "test.dat"
                (λ (port)
                  (decrypt #:port port
                           #:secret secret
                           #:num-ignored-bytes (bytevector-length trash-bytes))))])
         (log:debug "string written to file:" payload)
         (log:debug "string from file:" string-from-file)
         (string=? string-from-file payload))))))


(test-group
 "decrypt"

 (test-assert "decrypt-01"
   (= (decrypt-u8 197 0 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-02"
   (= (decrypt-u8 198 1 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-03"
   (= (decrypt-u8 199 2 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-04"
   (= (decrypt-u8 198 1 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-05"
   (= (decrypt-u8 199 2 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-06"
   (= (decrypt-u8 197 3 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-07"
   (= (decrypt-u8 198 4 (string->bytevector "abc"))
      100))

 (test-assert "decrypt-08"
   (= (decrypt-u8 199 5 (string->bytevector "abc"))
      100)))


(test-group
 "encrypt-decrypt-identity"

 (test-assert "identity"
   (let* ([u8 100]
          [secret-vector (string->bytevector "ABC")]
          [pos-in-input 10]
          [encrypt
           (λ (u8)
             (encrypt-u8 u8 pos-in-input secret-vector))]
          [decrypt
           (λ (u8)
             (decrypt-u8 u8 pos-in-input secret-vector))])
     (= (decrypt (encrypt u8)) u8))))


(test-end "crypt-test")
